package org.wm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.wm.constants.Constants;
import org.wm.constants.UserConstants;
import org.wm.domain.SysConfig;
import org.wm.exception.ServiceException;
import org.wm.mapper.SysConfigMapper;
import org.wm.service.ISysConfigService;
import org.wm.utils.Convert;
import org.wm.utils.RedisCache;
import org.wm.utils.StringUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * 参数配置 服务层实现
 * (已按照 Mybatis-Plus 混合模式进行改造)
 */
@RequiredArgsConstructor
@Service
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements ISysConfigService {

    private final RedisCache redisCache;

    @PostConstruct
    public void init() {
        loadingConfigCache();
    }

    @Override
    public String selectConfigByKey(String configKey) {
        String configValue = redisCache.getCacheObject(getCacheKey(configKey));
        if (StringUtils.isNotEmpty(configValue)) {
            return configValue;
        }
        SysConfig retConfig = this.getOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, configKey));
        if (retConfig != null) {
            redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
            return retConfig.getConfigValue();
        }
        return StringUtils.EMPTY;
    }

    @Override
    public boolean selectCaptchaOnOff() {
        String captchaOnOff = selectConfigByKey("sys.account.captchaOnOff");
        if (StringUtils.isEmpty(captchaOnOff)) {
            return true;
        }
        return Convert.toBool(captchaOnOff);
    }

    @Override
    public IPage<SysConfig> selectConfigPage(Page<SysConfig> page, SysConfig config) {
        return baseMapper.selectConfigList(page, config);
    }

    @Override
    public boolean insertConfig(SysConfig config) {
        boolean success = this.save(config);
        if (success) {
            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
        }
        return success;
    }

    @Override
    public boolean updateConfig(SysConfig config) {
        boolean success = this.updateById(config);
        if (success) {
            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
        }
        return success;
    }

    @Override
    @Transactional
    public void deleteConfigByIds(Long[] configIds) {
        for (Long configId : configIds) {
            SysConfig config = this.getById(configId);
            if (StringUtils.equals(UserConstants.YES, config.getConfigType())) {
                throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
            }
        }
        List<Long> ids = Arrays.asList(configIds);
        List<SysConfig> configsToDelete = this.listByIds(ids);
        if (this.removeByIds(ids)) {
            configsToDelete.forEach(config -> redisCache.deleteObject(getCacheKey(config.getConfigKey())));
        }
    }

    @Override
    public void loadingConfigCache() {
        List<SysConfig> configsList = this.list();
        for (SysConfig config : configsList) {
            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
        }
    }

    @Override
    public void clearConfigCache() {
        Collection<String> keys = redisCache.keys(Constants.SYS_CONFIG_KEY + "*");
        redisCache.deleteObject(keys);
    }

    @Override
    public void resetConfigCache() {
        clearConfigCache();
        loadingConfigCache();
    }

    @Override
    public String checkConfigKeyUnique(SysConfig config) {
        Long configId = config.getConfigId() == null ? -1L : config.getConfigId();
        SysConfig info = this.getOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, config.getConfigKey()));
        if (info != null && !info.getConfigId().equals(configId)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    private String getCacheKey(String configKey) {
        return Constants.SYS_CONFIG_KEY + configKey;
    }

    @Transactional
    public void testInsertA() {
        SysConfig sysConfig = new SysConfig();
        sysConfig.setConfigKey("testA2");
        sysConfig.setConfigValue("testA2");
        this.save(sysConfig);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void testInsertB() {
        SysConfig sysConfig = new SysConfig();
        sysConfig.setConfigKey("testB2");
        sysConfig.setConfigValue("testB2");
        this.save(sysConfig);
        throw new RuntimeException("撤回事务");
    }
}